package com.example.demo.service.sso;

import com.example.demo.config.EasyRbacConfig;
import com.labijie.caching.ICacheManager;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Function;

@Service
public class EasyRbacService {
    private ICacheManager cache;

    public EasyRbacService(ICacheManager cache, EasyRbacConfig easyRbacConfig, RestTemplate easyRbacClient) {
        this.cache = cache;
        this.easyRbacConfig = easyRbacConfig;
        this.easyRbacClient = easyRbacClient;
    }

    private RestTemplate easyRbacClient;
    private EasyRbacConfig easyRbacConfig;

    public LoginResult getAppToken() {
        String key = "easyRbacToken";
        LoginResult tokenObj = cache.get(key, EasyRbacConfig.Region, LoginResult.class);
        if (tokenObj == null) {
            String path = "/sso/UserLogin";
            HashMap<String, String> request = new HashMap<>();
            request.put("userName", easyRbacConfig.getAppId());
            request.put("password", easyRbacConfig.getAppSecret());
            request.put("appCode", easyRbacConfig.getAppId());
            ResponseEntity<LoginResult> loginResultResponseEntity = this.easyRbacClient.postForEntity(path, request, LoginResult.class);
            LoginResult body = loginResultResponseEntity.getBody();
            cache.set(key, body, body.getExpireIn() * 1000L, EasyRbacConfig.Region, false);
            tokenObj = body;
        }

        return tokenObj;
    }


    public UserInfo getEasyRbacUserInfo(String easyRbacUserToken) {
        String path = "/app/user/" + easyRbacUserToken;
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.set("authorization", "token " + this.getAppToken().getToken());
        HttpEntity<Object> httpEntity = new HttpEntity<>(httpHeaders);

        try {
            UserInfo result = this.easyRbacClient.exchange(this.easyRbacConfig.getUrl() + path, HttpMethod.GET, httpEntity, UserInfo.class).getBody();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }


    public List<UserResource> getUserResource(String rbacToken) {
        String key = "EasyRbac:Resource:" + rbacToken;
        List<UserResource> resources = this.cache.get(key, new ArrayList<UserResource>().getClass());
        if (resources == null) {
            String path = "app/resource/" + rbacToken;
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.set("authorization", "token " + this.getAppToken().getToken());
            HttpEntity<Object> httpEntity = new HttpEntity<>(httpHeaders);
            resources = this.easyRbacClient.exchange(this.easyRbacConfig.getUrl() + "/" + path, HttpMethod.GET, httpEntity, new ParameterizedTypeReference<List<UserResource>>() {
            }).getBody();
            this.cache.set(rbacToken, resources, 3600_000L, true);
        }
        return resources;
    }


    public boolean hasPermission(String localToken, String resourceName) {
        List<UserResource> userResource = this.getUserResource(localToken);
        return this.hasItem(userResource, x -> x.getResourceCode().equals(resourceName));
    }

    boolean hasItem(List<UserResource> resources, Function<UserResource, Boolean> condition) {
        for (UserResource item : resources) {
            if (item.getResourceCode() != null && condition.apply(item)) {
                return true;
            }
            if (item.getChildren()!=null && !item.getChildren().isEmpty()) {
                if (hasItem(item.getChildren(), condition)) {
                    return true;
                }
            }
        }
        return false;
    }
}
